package v1

import (
	"encoding/base64"
	"fmt"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
	"zhejianglab/gin-apiserver/pkg/logger"
	"zhejianglab/gin-apiserver/pkg/setting"

	"zhejianglab/gin-apiserver/model"
	"zhejianglab/gin-apiserver/pkg/util"

	"github.com/gin-gonic/gin"
)

// UploadFile upload file to disk
// @Produce  json
// @Tags file
// @Success 201 {object} gin.H "{"code":201,"msg":"UploadFile successfully"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"UpdateDownload: Download name is invalid"}"
// @Router /api/v1/file [post]
func UploadFile(c *gin.Context) {
	var err error

	file, err := c.FormFile("upload")
	algoName := c.Query("algo")

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Upload file failed for FormFile !" + err.Error()})
		return
	}

	fileName := file.Filename
	fileSub := path.Ext(fileName)
	name := fileName[:len(fileName)-len(fileSub)]

	md5Name := getFileBase64Name(fileName)
	src := filepath.Join(setting.FileSRC, md5Name)
	if err := c.SaveUploadedFile(file, src); err != nil {
		logger.Log.Info("Upload file  failed for" + err.Error())
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Upload file  failed for SaveUploadedFile !" + err.Error()})
		return
	}

	// 如果是压缩文件，解压
	if fileSub == ".zip" {

		fmt.Println("alforithm dir is", name)

		// 解压
		dstPath := filepath.Join("/data/algorithm/" + algoName + "/" + name + "/")
		util.DeCompress(src, dstPath)
		// 删除
		os.Remove(src)
		src = dstPath
	}

	fileInfo := model.FileInfo{
		Name:    fileName,
		MD5Name: md5Name,
		URL:     src,
	}

	data, err := model.AddNewUpload(&fileInfo)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Upload file failed  !" + err.Error()})
		return
	}
	fileData, ok := data.(*model.FileInfo)
	if !ok {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Upload file failed  !" + err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"status": http.StatusCreated, "message": "Upload file  successful!", "data": fileData})
	return

}

// getFileName make the file name to base style
func getFileBase64Name(name string) string {
	ext := path.Ext(name)
	fileName := strings.TrimSuffix(name, ext)

	timeFileName := fileName + time.Now().Format("2006/1/2 15:04:05")

	fileName = base64.RawURLEncoding.EncodeToString([]byte(timeFileName))

	return fileName + ext
}

// getFileName make the file name to md5 style
func getFileName(name string) string {
	ext := path.Ext(name)
	fileName := strings.TrimSuffix(name, ext)

	timeFileName := fileName + time.Now().Format("2006/1/2 15:04:05")

	fileName = util.EncodeMD5(timeFileName)

	return fileName + ext
}

// DeleteFile delete file to disk
// @Produce  json
// @Tags file
// @Success 201 {object} gin.H "{"code":201,"msg":"UploadFile successfully"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"UpdateDownload: Download name is invalid"}"
// @Router /api/v1/file/{filename} [delete]
func DeleteFile(c *gin.Context) {

	fileName := c.Param("fileName")
	myFileName, err := model.GetFileInfoWithName(fileName)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}

	path := setting.FileSRC + fileName
	err = os.Remove(path)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Delete file failed for !" + err.Error()})
		if !model.DeleteUpload(int(myFileName.ID)) {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Delete file  failed!", "file name": fileName})
		}
		return
	}

	if !model.DeleteUpload(int(myFileName.ID)) {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "Delete file  failed!", "file name": fileName})
	}

	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Delete file  successful!", "data": fileName})

}

// GetAllFileInfo get all files info from db
// @Produce  json
// @Tags file
// @Success 200 {object} gin.H "{"code":200,"msg":"GetAllFiles successfully!","data":{}}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"GetAllFiles failed!"}"
// @Router /api/v1/file [get]
func GetAllFileInfo(c *gin.Context) {
	data, err := model.GetAllUploads()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "GetAllCases successfully!", "data": data})

}

// DownloadFile download file to disk
// @Produce  json
// @Tags file
// @Success 201 {object} gin.H "{"code":201,"msg":"Download successfully"}"
// @Failure 500 {object} gin.H "{"code":500,"msg":"Download: Download name is invalid"}"
// @Router /api/v1/file/{fileName} [get]
func DownloadFile(c *gin.Context) {
	id := c.Query("job_id")
	filePathParam := c.Query("file_path")
	fileName := c.Param("fileName")
	filePath := ""
	c.Writer.Header().Add("Content-Type", "application/octet-stream")
	if id != "" {
		data, err := model.GetJob(id)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"status": http.StatusInternalServerError, "message": "no job_id found" + err.Error()})
			return
		}
		filePath = data.ResultPath + "/" + fileName
	} else if filePathParam != "" {
		filePath = filePathParam
	} else {
		filePath = setting.FileSRC + fileName
	}

	c.File(filePath)
}
